home *** CD-ROM | disk | FTP | other *** search
- /*
- parser suite - and / or / nothing / something parsers
-
- parser = [token] -> ([token],status)
-
- implemented as sideeffecting on [token], returns status.
- */
-
- # include "cc.h"
-
- STATUS p_andparse0 (p, q)
- /*
- Serial composition of parsers. Does
- first p then q. Put p's instructions on the
- top of the program stack, then layer q's above it.
-
- This version has full rewind of the input stream on
- failure, but this can be altered to single token
- lookahead by deleting the line of code marked.
- */
- PARSER p, q;
- {
- static status tok; /* why can't this be static? */
-
- MARK;
-
- tok = p ();
- if (BADSTATUS (tok)){ /* error */
- RELEASE;
- return tok;
- }
- tok = q ();
- if (BADSTATUS (tok)) /* error */
- {
- REWIND; /* remove this line for 1-token LA parsing */
- return tok;
- }
-
- pushDECR;
- RELEASE;
- return tok; /* succeed */
- }
-
-
- STATUS p_orparse0 (p, q)
- /*
- alternate composition of parsers. Tries p first,
- and if it doesnt work, tries q. Code corresponding
- to the successful parse is placed on the program stack.
- If both fail, the routine relies on p and q's auto-rewind
- mechanisms to do the rewind for it.
- */
- PARSER p, q;
- {
- static status tok; /* I don't see why this can't be static */
-
- tok = p ();
-
- if (BADSTATUS (tok)) /* error */
- tok = q (); /* retry */
-
- return tok; /* whatever */
- }
-
- STATUS p_many0 (p)
- /*
- parser which tries p any number of times
- until p fails, but returns success anyhow.
- */
- PARSER p;
- {
- int repeat = 0;
-
- while (GOODSTATUS(p ()))
- repeat++;
-
- switch(repeat){
- case 0: pushINCR; break;
- case 1: break;
- default:pushMANIP(-(repeat-1)); break;
- }
-
- return (SUCCESS);
- }
-
- STATUS p_iter0 (repeat, p)
- /*
- parser which tries p repeat number of times exactly
- */
- PARSER p;
- int repeat;
- {
- static int k;
- static status tok;
- MARK;
-
- k = repeat;
-
- while (k-->0) {
- tok = p ();
- if (BADSTATUS(tok)) {
- REWIND;
- return tok;
- }
- }
-
- switch(repeat){
- case 0: pushINCR; break;
- case 1: break;
- default:pushMANIP(-(repeat-1)); break;
- }
-
- RELEASE;
- return tok;
- }
-
-
- STATUS p_some0 (p)
- /*
- At least one repetition of parser p
- */
- PARSER p;
- {
- status tok;
-
- tok = p ();
- if (GOODSTATUS(tok)){
-
- tok = p_many0 (p);
- pushDECR; /* bound to succeed */
- return(tok);
- }
-
- return tok;
- }
-
- STATUS p_option0 (p)
- /* optionally p */
- PARSER p;
- {
- static status tok;
-
- tok = p();
- if (GOODSTATUS(tok))
- return tok;
-
- pushINCR;
- return(SUCCESS);
- }
-
-
- STATUS p_range0 (p)
- /*
- checks whether *pstr satisfies predicate p.
- p must take a TOKEN as arg. That is a mistake. It should be
- an int (a PARAM).
- */
- PREDICATE *p;
- {
- VALUE v;
-
- if ((*p) (*pstr))
- {
- v = lvbuff[pstr-buffer];
- MOVEON;
- pushVALUE(v);
- return (OK(v));
- }
- return (FAILURE);
- }
-
- STATUS p_attach (p,f)
- PARSER p;
- ACTION f;
- {
- static status tok;
-
- tok = p ();
- if (GOODSTATUS(tok)) {
-
- pushACTION(f);
- return tok;
- }
-
- return tok;
-
- }
-
- STATUS p_prepend (f,p)
- PARSER p;
- ACTION f;
- {
- static status tok;
- MARK;
-
- pushACTION(f);
-
- tok = p ();
- if (GOODSTATUS(tok)) {
- RELEASE;
- return tok;
- }
-
- REWIND;
-
- return tok;
- }
-
-
- STATUS p_hidden0 (p)
- PARSER p;
- /*
- parser which tries p, but doesnt moveon, just reports the result
- of p.
- */
- {
- static status tok;
- MARK;
-
-
- tok = p ();
-
- REWIND;
-
- if(GOODSTATUS(tok)) { /* we have to show we were here to keep in V(n) step */
- pushVALUE(tok);
- return tok;
- }
- return tok;
- }
-